﻿using Duende.IdentityServer.Models;
using Mapster;
using Service.Auth.Api.Application.Query;
using Service.Auth.Domain.AggregatesModel;
using Service.Auth.Model.Model.Dto;
using Service.Auth.Model.Model.QueryDto;
using Service.Core.Identity.Login;
using Service.Core.Redis.Services;
using Service.Core.Repository;
using Service.Framework;
using Service.Framework.Packet;
using Service.Framework.Utils;
using SqlSugar;

namespace Service.Auth.Api.Application.Query;

/// <summary>
/// 用户查询器
/// </summary>
/// <param name="userRepository"></param>
/// <param name="userRoleQuery"></param>
/// <param name="roleQueryService"></param>
/// <param name="userSession"></param>
/// <param name="redisService"></param>
/// <param name="rolePemissionsQuery"></param>
public class UserQueryService(
    IRepository<User, long> userRepository,
    UserRoleQueryService userRoleQuery,
    RoleQueryService roleQueryService,
    ILoginUserSession userSession,
    IRedisService redisService,
    RolePemissionsQueryService rolePemissionsQuery) : IScopedService
{
    /// <summary>
    /// 
    /// </summary>
    /// <param name="request"></param>
    /// <param name="createById"></param>
    /// <returns></returns>
    public async Task<PagedList<UserInfoDto>> QueryUserPage(QueryUserPageModel request, long? createById = null)
    {
        RefAsync<int> totalCount = 0;
        var exp = Expressionable.Create<User>()
            .AndIF(!request.RealName.IsNullOrWhiteSpace(), s => s.RealName.Contains(request.RealName))
            .AndIF(createById.HasValue, s => s.CreateById.Equals(createById.Value))
            .AndIF(!request.Account.IsNullOrWhiteSpace(), s => s.Account.Contains(request.Account));
        var datas = await userRepository.Db.Queryable<User>().Where(exp.ToExpression())
            .Includes(x => x.UserSystemRoles)
            .WhereIF(request.SystemIds != null && request.SystemIds.Length > 0, x => x.UserSystemRoles.Any(z => request.SystemIds.Contains(z.SystemId)))
            .ToPageListAsync(request.PageIndex, request.PageSize, totalCount);
        var result = datas.Adapt<List<UserInfoDto>>();
        return new PagedList<UserInfoDto>(result, request.PageIndex, request.PageSize, totalCount);
    }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="request"></param>
    /// <returns></returns>
    public async Task<UserInfoDto> QueryUserDtoById(QueryUserById request)
    {
        var result = await QueryUserById(request.Id);
        return result.Adapt<UserInfoDto>();
    }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="id"></param>
    /// <returns></returns>
    public async Task<User> QueryUserById(long id)
    {
        return await userRepository.Db.Queryable<User>().Where(s => s.Id.Equals(id))
            .Includes(x => x.UserSystemRoles).FirstAsync();
    }


    /// <summary>
    /// 
    /// </summary>
    /// <param name="account"></param>
    /// <returns></returns>
    public async Task<User> QueryUserByAccount(string account)
    {
        return await userRepository.Db.Queryable<User>().Where(s => s.Account.Equals(account))
            .Includes(x => x.UserSystemRoles).FirstAsync();
    }


    /// <summary>
    /// 
    /// </summary>
    /// <param name="userId"></param>
    /// <returns></returns>
    public async Task<List<PermissionDto>> QueryUserPermissionsById(long? userId = null)
    {
        if (userId == null)
            userId = long.Parse(userSession.IdentityName);
        var userSystemRoles = await userRoleQuery.QueryUserRoleByUserId(userId.Value);
        var roleIds = userSystemRoles.Select(s => s.RoleId).ToList();
        var result = await rolePemissionsQuery.QueryRolePemissionByRoles(roleIds);
        return result;
    }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="roleNums"></param>
    /// <param name="createById"></param>
    /// <returns></returns>
    public async Task<List<IdName<long, string>>> QueryUserSelect(List<string> roleNums, long? createById = null)
    {
        var datas = await userRepository.Db.Queryable<User, UserSystemRole>((u, usr) => new JoinQueryInfos(JoinType.Left, u.Id.Equals(usr.UserId)))
            .Where((u, usr) => roleNums.Contains(usr.RoleNum))
            .WhereIF(createById.HasValue, (u, usr) => u.CreateById.Equals(createById.Value)).Distinct()
            .Select((u, usr) => u)
            .ToListAsync();
        var result = datas.Select((u, usr) => new IdName<long, string>(u.Id, u.Account)).ToList();
        return result;
    }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="user"></param>
    /// <param name="seconds"></param>
    /// <returns></returns>
    public async Task<LoginUserInfo> BuildLoginUserInfo(User user)
    {
        var roleIds = user.UserSystemRoles.Select(s => s.RoleId).ToList();
        List<Role> roles = await roleQueryService.QueryRoleByIds(roleIds);
        var loginUserInfo = new LoginUserInfo(user.Id, user.Account, user.RealName,
                  roles.Select(s => s.RoleNum).ToList(), roles.Select(s => s.Level).Max(), user.Picture, user.Phone);

        return loginUserInfo;
    }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="id"></param>
    /// <param name="seconds"></param>
    /// <returns></returns>
    public async Task<LoginUserInfo> BuildLoginUserInfo(long id)
    {
        var user = await QueryUserById(id);
        return await BuildLoginUserInfo(user);
    }
}